import React, { Component } from 'react';
import { Row, Col } from 'antd';
import { Toast, Modal, Badge, List } from 'antd-mobile';
import styles from './index.less';
import SocketEvent from '@/service/event';
import config from '@/config';
import { error, log } from '@/utils/log-utils';
import { btnSound, playSound } from '@/utils/sounds-res';
import AdvancedBtn from "@/button";
import {JOIN_ROOM_TYPE_RANDOM} from "@/utils/const-utils";
import AdvancedSpin from "@/spinner";

/**
 * 匹配界面(随机模式)
 */
class PlayerRandom extends Component {

  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      text: null,
      // 正在换桌的状态
      swapDesk: false,
      // 房间信息
      roomUser: null,
      roomEnemy: null,
      // 房间准备倒计时
      timeout: null,
      // 记录房间号
      roomId: null,
    };

    // 事件id
    this.enemyOfflineRespId = 'playerEnemyOfflineRespId';
    this.enemyOnlineRespId = 'playerEnemyOnlineRespId';
    this.enemyJoinRoomRespId = 'playerEnemyJoinRoomRespId';
    this.enemyLeaveRoomRespId = 'playerEnemyLeaveRoomRespId';
    this.syncRoomDataRespId = 'playerSyncRoomDataRespId';
    this.matchSuccessRespId = 'playerMatchSuccessRespId';
    this.allowInBattleId = 'playerAllowInBattleId';
    this.kickUserId = 'playerKickUserId';

    this.unRegisterServices = [];
    this.unRegisterServices.push(this.enemyOfflineRespId);
    this.unRegisterServices.push(this.enemyOnlineRespId);
    this.unRegisterServices.push(this.enemyJoinRoomRespId);
    this.unRegisterServices.push(this.enemyLeaveRoomRespId);
    this.unRegisterServices.push(this.syncRoomDataRespId);
    this.unRegisterServices.push(this.matchSuccessRespId);
    this.unRegisterServices.push(this.allowInBattleId);
    this.unRegisterServices.push(this.kickUserId);
  }

  componentDidMount() {
    const { userId } = this.props;
    log('进入匹配页面(随机模式) userId: ', userId);
    // 初始化房间数据
    this.initRoomData();
    // 开启事件监听
    this.startEventListen();
  }

  /**
   * 初始化房间数据
   */
  initRoomData = () => {
    const { userId, roomId, roomUser, roomEnemy } = this.props;
    // 用户携带房间号进入则是刚完成PK的玩家
    if (roomId) {
      log(`已存在对战房间号，同步房间数据, roomId: ${roomId}, 双方信息为(可能):`, roomUser, roomEnemy);
      // 请求同步房间数据
      this.setState({
        roomId,
        roomUser: roomUser ? { ...roomUser, isReady: false } : null,
        roomEnemy: roomEnemy ? { ...roomEnemy, isReady: false } : null,
      });
      SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
        userId: userId,
        roomId: roomId,
      }, resp => {
        if (resp.code !== 'success') {
          Modal.alert('系统提示', resp.msg, [
            {
              text: '返回', onPress: () => {
                playSound(btnSound);
                this.props.goBack();
              },
            },
          ]);
        }
      });
    } else {
      log('开始申请加入房间 userId: ', userId);
      setTimeout(async () => {
        await this.setState({ userId });
        // 申请加入房间
        this.applyJoinRoom();
      }, 0);
    }
  };

  /**
   * 事件监听
   */
  startEventListen = () => {
    // 对方离线监听
    SocketEvent.register('enemyOfflineRespApi', this.enemyOfflineRespId, resp => {
      log('用户离线消息，返回：', resp);
      if (resp.code === 'success') {
        // 同步房间状态
        SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
          userId: this.props.userId,
          roomId: this.state.roomId,
        }, resp => {
          if (resp.code !== 'success') {
            Toast.show(resp.msg);
          }
        });
      }
    });
    // 对方上线监听
    SocketEvent.register('enemyOnlineRespApi', this.enemyOnlineRespId, resp => {
      log('对方上线消息，返回：', resp);
      if (resp.code === 'success') {
        // 同步房间状态
        SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
          userId: this.props.userId,
          roomId: this.state.roomId,
        }, resp => {
          if (resp.code !== 'success') {
            Toast.show(resp.msg);
          }
        });
      }
    });

    // 同步房间信息结果
    SocketEvent.register('syncRoomDataRespApi', this.syncRoomDataRespId, resp => {
      log(`同步房间信息返回：`, resp);
      if (resp.code === 'success') {
        const { roomUser, roomEnemy } = resp.data;
        // 保存数据
        this.setState({ roomUser, roomEnemy });
        // 若倒计时为空，则进行倒计时，若已有，则直接跳过(避免重置倒计时)
        if (!this.intervalId) {
          // 启动倒计时
          this.userReadyTimeout();
        }
      } else {
        error('房间数据异常，错误信息：', resp.msg);
        // 房间已被解散
        Toast.fail(resp.msg, 2, () => {
          // 回到登录页面
          this.props.goBack();
        });
      }
    });

    // 对手加入我方房间监听
    SocketEvent.register('enemyJoinRoomRespApi', this.enemyJoinRoomRespId, resp => {
      log('对方加入我方房间，resp：', resp);
      if (resp.code === 'success') {
        // 主动同步房间数据
        log('同步房间中的对手方数据，roomId: ', this.state.roomId);
        SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
          userId: this.props.userId,
          roomId: this.state.roomId,
        }, resp => {
          if (resp.code !== 'success') {
            Toast.show(resp.msg);
          }
        });
      }
    });

    // 对手离开房间监听
    SocketEvent.register('enemyLeaveRoomRespApi', this.enemyLeaveRoomRespId, resp => {
      log('对方离开了我方房间，返回：', resp);
      this.setState({ roomEnemy: null });
      // 主动同步一次房间的状态
      SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
        userId: this.props.userId,
        roomId: this.state.roomId,
      }, resp => {
        if (resp.code !== 'success') {
          Toast.show(resp.msg);
        }
      });
    });

    // 双方已准备，但还未保存数据
    SocketEvent.register('matchSuccessRespApi', this.matchSuccessRespId, (resp) => {
      log('服务器返回双方已准备信息，resp: ', resp);
      if (resp.code === 'success') {
        this.setState({ loading: true, text: '' });
      } else {
        Toast.show(resp.msg);
      }
    });

    // 允许进入对局
    SocketEvent.register('allowInBattleApi', this.allowInBattleId, (resp) => {
      log('服务器允许双方进入对局，resp: ', resp);
      if (resp.code === 'success') {
        const { userId } = this.props;
        const { roomId } = this.state;
        const { battleId, playOne, playTwo} = resp.data;
        const roomUser = playOne.userId === userId ? playOne : playTwo;
        const roomEnemy = playOne.userId === userId ? playTwo : playOne;
        log(`即将进入对战页面, userId: ${roomUser.userId}, roomId: ${roomId}`);
        this.props.matchSuccess(battleId, roomId, roomUser, roomEnemy);
      } else {
        Toast.show(resp.msg);
      }
    });

    /**
     * 被踢出房间
     */
    SocketEvent.register('kickUserRespApi', this.kickUserId, (resp) => {
      log('被房主踢出房间，resp: ', resp);
      if (resp.code === 'success') {
        const { userId, roomId } = resp.data;
        const { roomUser } = this.state;
        log('被房主踢出房间，用户信息为: ', roomUser);

        if(roomUser && roomUser.userId === userId && roomUser.roomId === roomId) {
          Modal.alert('系统提示', '您被房主请出了房间', [
            {
              text: '确认', onPress: () => {
                playSound(btnSound);
              },
            },
          ]);
          // 返回上一页面
          this.props.goBack();
        }
      } else {
        Toast.show(resp.msg);
      }
    });
  };

  /**
   * 申请加入房间
   */
  applyJoinRoom = () => {
    const { userId } = this.props;
    const { roomId } = this.state;
    this.setState({ loading: false });
    log(`开始服务器发送加入房间的请求:`, { userId: userId });
    SocketEvent.emit(this.props.socket, 'joinRoomApi', {
      userId: userId,
      joinType: JOIN_ROOM_TYPE_RANDOM,
      historyRoomIds: roomId ? [roomId] : [],
    }, resp => {
      log('申请加入房间结果返回，resp: ', resp);
      // this.setState({ loading: false });
      if (resp.code === 'success') {
        // 记录实际加入的房间号
        this.setState({ roomId: resp.data.roomId });
      } else {
        Modal.alert('系统提示', resp.msg, [
          {
            text: '确定', onPress: () => {
              playSound(btnSound);
              this.props.goBack();
            },
          },
        ]);
      }
    });
  };

  /**
   * 用户未准备时进行倒计时运算，超时退出房间
   */
  userReadyTimeout = () => {
    this.setState({ timeout: config.normalReadyTimeout });
    // 进入房间后开始读秒
    this.intervalId = setInterval(() => {
      // 注意实时获取玩家状态
      const { roomUser, roomEnemy } = this.state;
      let { timeout } = this.state;

      // 玩家为`准备`状态停止读秒
      if (roomUser && roomUser.isReady) {
        clearInterval(this.intervalId);
        delete this.intervalId;
        return false;
      }
      --timeout;
      // 对方已准备，读秒时间缩短
      if (roomEnemy && roomEnemy.isReady) {
        timeout = Math.min(timeout, config.noReadyTimeout);
      }
      if (timeout < 0) {
        clearInterval(this.intervalId);
        delete this.intervalId;
        log('准备进行超时离开，roomId：', this.state.roomId);
        // 通知服务器将该用户从房间中踢出
        SocketEvent.emit(this.props.socket, 'leaveRoomApi', {
          userId: this.props.userId,
          roomId: this.state.roomId,
        }, resp => {
          log('离开房间结果返回: ', resp);
          if (resp.code === 'success') {
            // 父页面刷新
            this.props.goBack();
          } else {
            log('无法离开该房间', this.state.roomId);
          }
        });
        return false;
      }
      // 同步状态
      this.setState({ timeout });
    }, 1000);
  };

  /**
   * 开始按钮
   */
  startClick = async e => {
    playSound(btnSound);
    const { roomEnemy, roomUser } = this.state;
    // 若房间内的用户已全部准备，则不强制退出对局
    if (roomEnemy && roomEnemy.isReady) {
      this.setState({ localUserAllReady: true });
    } else if (roomUser && roomUser.isReady) {
      // Toast.show('您已准备完成');
      return;
    }
    log('点击『开始』按钮，roomId:', this.state.roomId);
    // 通知服务器，玩家已准备
    SocketEvent.emit(this.props.socket, 'userReadyApi', {
      userId: this.props.userId,
      roomId: this.state.roomId,
    }, resp => {
      log('用户已准备，开始同步房间信息,roomId:', this.state.roomId, resp);
      // 通知后主动请求房间的数据
      SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
        userId: this.props.userId,
        roomId: this.state.roomId,
      }, resp => {
        if (resp.code !== 'success') {
          Toast.show(resp.msg);
        }
      });
    });
  };

  /**
   * 换桌按钮
   */
  swapDeskClick = e => {
    playSound(btnSound);

    // 清除当前计时器并重新累计定时器
    clearInterval(this.intervalId);
    delete this.intervalId;

    this.setState({
      loading: false,
      swapDesk: true,
    });

    // 防止短时间内重复换桌
    setTimeout(() => {
      this.setState({ swapDesk: false });
    }, 2000);

    // 换桌，实际操作是先离开房间，后申请加入房间
    SocketEvent.emit(this.props.socket, 'leaveRoomApi', {
      userId: this.props.userId,
      roomId: this.state.roomId,
    }, resp => {
      log('离开房间结果返回: ', resp);
      // 申请加入房间
      this.applyJoinRoom();
    });
  };

  goBack = e => {
    playSound(btnSound);
    const { roomId } = this.state;
    if (roomId) {
      // this.setState({ loading: true, text: '请求离开中...' });
      // 通知服务器将该用户从房间中踢出
      log(`用户[${this.props.userId}]即将退出房间[${roomId}]`);
      SocketEvent.emit(this.props.socket, 'leaveRoomApi', {
        userId: this.props.userId,
        roomId: roomId,
      }, resp => {
        this.setState({ loading: false });
        log('离开房间结果返回: ', resp);
        if (resp.code === 'success') {
          this.props.goBack();
        } else {
          Toast.show(resp.msg);
        }
      });
    }
  };

  /**
   * 踢出对手
   */
  kickEnemyHandle = () => {
    // 踢人核心逻辑
    const kickHandleCore = () => {
      const { roomEnemy } = this.state;
      if(!roomEnemy) {
        Toast.show('对方已不在房间中');
        return;
      }
      // 发起踢人请求
      const { userId } = this.props;
      const {userId: kickUserId, roomId} = roomEnemy;

      SocketEvent.emit(this.props.socket, 'kickUserApi', {
        userId: userId,
        kickUserId: kickUserId,
        roomId: roomId,
      }, resp => {
        if (resp.code === 'success') {
          // 同步房间数据
          SocketEvent.emit(this.props.socket, 'syncRoomDataApi', {
            userId: userId,
            roomId: roomId,
          }, resp => {
            if (resp.code !== 'success') {
              Modal.alert('系统提示', resp.msg, [
                {
                  text: '返回', onPress: () => {
                    playSound(btnSound);
                    this.props.goBack();
                  },
                },
              ]);
            }
          });
        } else {
          Toast.show(resp.msg);
        }
      });
    }

    // 提示
    this.kickModal = Modal.alert('系统提示', '确定踢出对手吗?', [
      {text: '取消', onPress: () => playSound(btnSound)},
      {
        text: '确认', onPress: () => {
          playSound(btnSound);
          kickHandleCore();
        },
      },
    ]);
  }

  /**
   * 组件销毁时将所有已注册的监听卸载掉
   */
  componentWillUnmount() {
    clearInterval(this.intervalId);
    this.kickModal && this.kickModal.close();
    SocketEvent.unRegister(this.unRegisterServices);
  }

  render() {
    const { roomUser, roomEnemy, timeout } = this.state;
    return (
      <div className={styles.pk}>
        <div className={styles.pkBoard}>
          <div className={styles.pkTitle}>
            <div className={styles.subject}>
              <div className={styles.icon}/>
              <span>对战平台<label>{(!roomUser || !roomUser.roomId) ? '' : `(${roomUser.roomId}号桌)`}</label></span>
            </div>
            <div className={styles.extends}>
              <Badge text="踢" hot style={{ marginRight: 10 }} hidden={!(roomUser?.isRoomAdmin && roomEnemy)} onClick={this.kickEnemyHandle} />
              <Badge text="锁定" hot style={{ backgroundColor: '#f19736' }} hidden={!(roomUser?.isRoomAdmin)} />
            </div>
          </div>
          <div className={styles.pkLineItem}>
            <div style={{ display: roomUser ? 'block' : 'none' }}>
              <div className={styles.border}>
                <Badge
                  text={roomUser?.first ? '先手' : '后手'}
                  corner
                  className={styles.badge}
                  style={{ backgroundColor: roomUser?.first ? '#ff5b05' : '#1e1e1a'}}
                />
                <Row>
                  <Col span={4} className={styles.titleLeft}>名称:</Col>
                  <Col span={11} className={styles.name}>{roomUser?.userName}</Col>
                  <Col span={9} className={styles.timeout}>
                    {roomUser?.isReady ? '准备' : timeout}
                    <span hidden={!roomUser || !roomUser.isOffline}>离线</span>
                  </Col>
                </Row>
                <Row>
                  <Col span={4} className={styles.titleLeft}>积分:</Col>
                  <Col span={10} className={styles.score}>{roomUser?.score}</Col>
                  <Col span={6} className={styles.title}>胜率:</Col>
                  <Col span={4} className={styles.scoreRight}>
                    {roomUser && roomUser.pkTotalCount > 0 ? Math.floor((roomUser.pkWinCount / roomUser.pkTotalCount) * 100) : 0}%
                  </Col>
                </Row>
              </div>
            </div>
          </div>
          <div className={styles.pkLineItem}>
            <div className={styles.mask} style={{ display: (!roomUser || roomEnemy) ? 'none' : 'block' }}>
              <div className={styles.content}>等待玩家加入</div>
            </div>
            <div style={{ display: roomEnemy ? 'block' : 'none' }}>
              <div className={styles.border}>
                <Badge
                  text={roomEnemy?.first ? '先手' : '后手'}
                  corner
                  className={styles.badge}
                  style={{ backgroundColor: roomEnemy?.first ? '#ff5b05' : '#1e1e1a'}}
                />
                <Row>
                  <Col span={4} className={styles.titleLeft}>名称:</Col>
                  <Col span={11} className={styles.name}>{roomEnemy?.userName}</Col>
                  <Col span={9} className={styles.timeout}>
                    {roomEnemy?.isReady ? '准备' : ''}
                    <span hidden={!roomEnemy || !roomEnemy.isOffline}>离线</span>
                  </Col>
                </Row>
                <Row>
                  <Col span={4} className={styles.titleLeft}>积分:</Col>
                  <Col span={10} className={styles.score}>{roomEnemy?.score}</Col>
                  <Col span={6} className={styles.title}>胜率:</Col>
                  <Col span={4} className={styles.scoreRight}>
                    {roomEnemy && roomEnemy.pkTotalCount > 0 ? Math.floor((roomEnemy.pkWinCount / roomEnemy.pkTotalCount) * 100) : 0}%
                  </Col>
                </Row>
              </div>
            </div>
          </div>
          <div className={styles.pkLineItem}>
            <Row style={{ marginTop: '0.3rem' }}>
              <Col span={2}/>
              <Col span={6}>
                <AdvancedBtn type="normal" text="开始" disabled={roomUser?.isReady} onClick={(e) => this.startClick(e)} />
              </Col>
              <Col span={1}/>
              <Col span={6}>
                <AdvancedBtn
                  type="normal" text="换桌"
                  disabled={this.state.swapDesk || (roomUser?.isReady && roomEnemy?.isReady)}
                  onClick={e => this.swapDeskClick(e)}/>
              </Col>
              <Col span={1}/>
              <Col span={6}>
                <AdvancedBtn
                  type="danger"
                  text="返回"
                  disabled={roomUser?.isReady && roomEnemy?.isReady}
                  onClick={e => this.goBack(e)}/>
              </Col>
              <Col span={2}/>
            </Row>
          </div>
        </div>
        <AdvancedSpin text={this.state.text} show={this.state.loading}/>
      </div>
    );
  }
}

export default PlayerRandom;
